const crypto = require('crypto');

const utils = {
	
	// sha1加密
	sha1: (str) => {
		const shasum = crypto.createHash("sha1");
		shasum.update(str);
	
		str = shasum.digest("hex");
	
		return str
	},
	// aes 加密
	aesEncrypt: (key, iv, data) => {
		
		const encipher = crypto.createCipheriv('aes-256-cbc', key, iv);
		encipher.setAutoPadding(false);
		
		let rawmsg = Buffer.from(data);
		rawmsg = utils.aesPKCS7Encode(rawmsg);
		
		const encryptBuffer = Buffer.concat([encipher.update(rawmsg), encipher.final()]);
		
		return encryptBuffer.toString('base64');
	},
	// aes 解密
	aesDecrypt: (key, iv, data, rtype) => {
		
		const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
		decipher.setAutoPadding(false);
		
		let decryptBuffer = Buffer.concat([decipher.update(data, 'base64'), decipher.final()]);
		decryptBuffer = utils.aesPKCS7Decode(decryptBuffer);
		
		if (rtype === 'buffer') return decryptBuffer;
		
		return decryptBuffer.toString('utf-8');
	},
	aesPKCS7Decode: (buff) => {
		/*
		 *去除尾部自动填充的内容
		 */
		let padContent = buff[buff.length -1];
		if(padContent < 1 || padContent > 32){
			padContent = 0;
		}
		let padLen = padContent;
		return buff.slice(0, buff.length - padLen);
	},
	aesPKCS7Encode: (buff) => {
		let blockSize = 32;
		let needPadLen = 32 - buff.length % 32;
		if( needPadLen == 0) {
			needPadLen = blockSize;
		}
		let pad = new Buffer(needPadLen);
		pad.fill(needPadLen);
		let newBuff = Buffer.concat([buff, pad]);
		return newBuff;
	},
	// 微信消息加解密技术介绍
	// https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/Before_Develop/Technical_Plan.html
	// 微信消息加密
	wxmsgEncrypt: (appid, token, encodingAESKey, data) => {
		const key = Buffer.from(encodingAESKey + '=', 'base64');
		const iv = key.slice(0, 16);
		
		const random16 = crypto.pseudoRandomBytes(16);
		const msg = Buffer.from(data);
		const msgLength = new Buffer(4);
		msgLength.writeUInt32BE(msg.length, 0);
		
		// 参照微信官方文档 需返回 buffer: 随机16字节 + data.length(4字节) + msg + appid
		const rawmsg = Buffer.concat([random16, msgLength, msg, Buffer.from(appid)]);
		
		// 加密
		// msg_encrypt = Base64_Encode(AES_Encrypt [random(16B)+ msg_len(4B) + msg + appid])
		const msg_encrypt = utils.aesEncrypt(key, iv, rawmsg);
		
		const timestamp = parseInt(Date.now() / 1000);
		const nonce = crypto.pseudoRandomBytes(9).toString('base64');
		
		// msg_signature=sha1(sort(Token、timestamp、nonce, msg_encrypt))
		const signature = utils.sha1([token, timestamp, nonce, msg_encrypt].sort().join(''));
		
		return {
			Encrypt: msg_encrypt,
			MsgSignature: signature,
			TimeStamp: timestamp,
			Nonce: nonce
		}
	},
	// 微信消息解密
	wxmsgDecrypt: (encodingAESKey, data) => {
		const key = Buffer.from(encodingAESKey + '=', 'base64');
		const iv = key.slice(0, 16);
		
		// 解密
		const rawmsgBuffer = utils.aesDecrypt(key, iv, data, 'buffer');
		const rawmsg = rawmsgBuffer.toString('utf-8');
		// 参照微信官方文档 需返回 buffer: 随机16字节 + data.length(4字节) + msg + appid
		const msglenBuffer = rawmsgBuffer.slice(16, 20);
		const msglen = msglenBuffer.readUInt32BE();
		
		const msg = rawmsg.substr(20, msglen);
		const appid = rawmsg.substring(20 + msglen);
		
		return {
			len: msglen,
			msg: msg,
			appid: appid
		};
	},
	
	// xml -> json
	xmlToJson: (str) => {
		const props = str.replace('<xml>', '')
			.replace('</xml>', '')
			.replace(/><!\[CDATA\[/g, '>')
			.replace(/\]\]><\//g, '</')
			.split('\n')
			.filter(x => x);
		
		const obj = {};
		
		props.forEach(x => {
			const key = x.substring(x.indexOf('<') + 1, x.indexOf('>'));
			const value = x.substring(x.indexOf('>') + 1, x.lastIndexOf('</'));
			if (key) obj[key] = value;
		});
		
		return obj;
	},
	// json -> xml
	jsonToXml: (obj) => {
		const nodes = [];
		for (let key in obj) {
			nodes.push(`<${key}>${obj[key]}</${key}>`);
		}
		
		return `<xml>${nodes.join('')}</xml>`;
	},
	
	// 获取应用标识
	getapp: (str) => {
		const [appid] = str.split('_');
		return appid;
	}
	
}

module.exports = utils;